home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / Online / Term / Extras / Source / term-source.lha / Buffer.c < prev    next >
C/C++ Source or Header  |  1996-10-20  |  28KB  |  1,416 lines

  1. /*
  2. **    Buffer.c
  3. **
  4. **    Auxilary routines for text buffer/capture management.
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=3
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* Search string window gadgets. */
  17.  
  18. enum    {    GAD_STRING=1000,GAD_OK,GAD_CANCEL };
  19.  
  20.     /* Maximum size of an allocated line string. */
  21.  
  22. #define STRING_SIZE    (1 + 255 + 1)
  23.  
  24.     /* How many strings to include in a single puddle. */
  25.  
  26. #define STRING_COUNT    10
  27.  
  28.     /* The number of lines the buffer will grow. */
  29.  
  30. #define BUFFER_GROW    100
  31.  
  32.     /* Memory pool header. */
  33.  
  34. STATIC APTR BufferPoolHeader;
  35.  
  36.     /* Word separator characters. */
  37.  
  38. STATIC BYTE WordSeparators[256] =
  39. {
  40.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  41.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  42.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  43.     0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
  44.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  45.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  46.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  47.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  48.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  49.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  50.     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  51.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  52.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  53.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  54.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  55.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0
  56. };
  57.  
  58.     /* AllocString(STRPTR String,LONG Len):
  59.      *
  60.      *    Allocate space for a string, new pooled version.
  61.      */
  62.  
  63. STATIC STRPTR
  64. AllocString(STRPTR String,LONG Len)
  65. {
  66.     STRPTR Mem;
  67.  
  68.     if(Len > 255)
  69.         Len = 255;
  70.  
  71.     if(Mem = (STRPTR)AsmAllocPooled(BufferPoolHeader,1 + Len + 1,SysBase))
  72.     {
  73.         *Mem++ = Len;
  74.  
  75.         if(Len)
  76.             CopyMem(String,Mem,Len);
  77.  
  78.         Mem[Len] = 0;
  79.     }
  80.  
  81.     return(Mem);
  82. }
  83.  
  84.     /* FreeString(STRPTR String):
  85.      *
  86.      *    Free the space occupied by a string, new pooled version.
  87.      */
  88.  
  89. STATIC VOID
  90. FreeString(STRPTR String)
  91. {
  92.     AsmFreePooled(BufferPoolHeader,&String[-1],1 + String[-1] + 1,SysBase);
  93. }
  94.  
  95.     /* AddLine(STRPTR Line,LONG Size):
  96.      *
  97.      *    Add a line to the display buffer.
  98.      */
  99.  
  100. VOID
  101. AddLine(STRPTR Line,LONG Size)
  102. {
  103.         /* Are we still to update the buffer contents? */
  104.  
  105.     if(!BufferClosed)
  106.     {
  107.         ULONG Signals;
  108.         BOOL Notify;
  109.  
  110.         Signals = NULL;
  111.  
  112.         ObtainSemaphore(&BufferSemaphore);
  113.  
  114.             /* Is the buffer array initialized? */
  115.  
  116.         if(BufferLines)
  117.         {
  118.                 /* Check for limit. */
  119.  
  120.             if(Config->CaptureConfig->MaxBufferSize && BufferSpace >= Config->CaptureConfig->MaxBufferSize)
  121.             {
  122.                 LONG i;
  123.  
  124.                 BufferSpace -= BufferLines[0][-1];
  125.  
  126.                 FreeString(BufferLines[0]);
  127.  
  128.                 for(i = 1 ; i < MaxLines ; i++)
  129.                     BufferLines[i - 1] = BufferLines[i];
  130.  
  131.                 Lines--;
  132.  
  133.                     /* Tell the buffer task to
  134.                      * refresh the display.
  135.                      */
  136.  
  137.                 Signals = SIG_MOVEUP;
  138.             }
  139.             else
  140.             {
  141.                     /* We've reached the last line in the buffer. */
  142.  
  143.                 if(Lines == MaxLines || ((Lines & 3) == 3 && AvailMem(MEMF_LARGEST) <= Config->CaptureConfig->BufferSafetyMemory))
  144.                 {
  145.                     STRPTR *MoreBuffer;
  146.  
  147.                         /* Allocate space for some more lines. */
  148.  
  149.                     if(MoreBuffer = (STRPTR *)AllocVecPooled((MaxLines + BUFFER_GROW) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  150.                     {
  151.                         BufferChanged = TRUE;
  152.  
  153.                             /* Copy the old lines to the new
  154.                              * buffer.
  155.                              */
  156.  
  157.                         CopyMem(BufferLines,MoreBuffer,Lines * sizeof(STRPTR));
  158.  
  159.                             /* Free the old lines. */
  160.  
  161.                         FreeVecPooled(BufferLines);
  162.  
  163.                             /* Set the new buffer. */
  164.  
  165.                         MaxLines += BUFFER_GROW;
  166.  
  167.                         BufferLines = MoreBuffer;
  168.                     }
  169.                     else
  170.                     {
  171.                         BufferChanged = TRUE;
  172.  
  173.                             /* We couldn't get enough memory
  174.                              * to extend the number of lines
  175.                              * in the buffer, so we'll have
  176.                              * to wrap the contents of the
  177.                              * buffer around.
  178.                              */
  179.  
  180.                         if(Lines)
  181.                         {
  182.                             LONG i;
  183.  
  184.                             BufferSpace -= BufferLines[0][-1];
  185.  
  186.                             FreeString(BufferLines[0]);
  187.  
  188.                             for(i = 1 ; i < MaxLines ; i++)
  189.                                 BufferLines[i - 1] = BufferLines[i];
  190.  
  191.                             Lines--;
  192.  
  193.                                 /* Tell the buffer task to
  194.                                  * refresh the display.
  195.                                  */
  196.  
  197.                             Signals = SIG_MOVEUP;
  198.                         }
  199.                     }
  200.                 }
  201.             }
  202.  
  203.                 /* Allocate a new line and copy the buffer contents
  204.                  * into it.
  205.                  */
  206.  
  207.             if(BufferLines[Lines] = AllocString(Line,Size))
  208.             {
  209.                 BufferChanged = TRUE;
  210.  
  211.                 Lines++;
  212.  
  213.                 BufferSpace += Size;
  214.             }
  215.  
  216.             Notify = TRUE;
  217.         }
  218.         else
  219.             Notify = FALSE;
  220.  
  221.         ReleaseSemaphore(&BufferSemaphore);
  222.  
  223.         if(Notify)
  224.         {
  225.                 /* Tell the buffer tasks to update the displays. */
  226.  
  227.             if(!Signals)
  228.                 Signals = SIG_UPDATE;
  229.  
  230.             NotifyBuffer(&BufferTaskSemaphore,&BufferInfoData,Signals);
  231.             NotifyBuffer(&ReviewTaskSemaphore,&ReviewInfoData,Signals);
  232.         }
  233.     }
  234. }
  235.  
  236.     /* DeleteBuffer():
  237.      *
  238.      *    Delete buffer resources.
  239.      */
  240.  
  241. VOID
  242. DeleteBuffer()
  243. {
  244.     FreeVecPooled(BufferLines);
  245.     BufferLines = NULL;
  246.  
  247.     if(BufferPoolHeader)
  248.     {
  249.         AsmDeletePool(BufferPoolHeader,SysBase);
  250.         BufferPoolHeader = NULL;
  251.     }
  252. }
  253.  
  254.     /* CreateBuffer():
  255.      *
  256.      *    Allocate buffer resources.
  257.      */
  258.  
  259. BOOL
  260. CreateBuffer()
  261. {
  262.     if(BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  263.     {
  264.             /* Create a memory pool header if possible. */
  265.  
  266.         if(BufferPoolHeader = AsmCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT,SysBase))
  267.             return(TRUE);
  268.         else
  269.         {
  270.             FreeVecPooled(BufferLines);
  271.             BufferLines = NULL;
  272.         }
  273.     }
  274.  
  275.     return(FALSE);
  276. }
  277.  
  278.     /* FreeBuffer():
  279.      *
  280.      *    Release the contents of the text buffer.
  281.      */
  282.  
  283. VOID
  284. FreeBuffer()
  285. {
  286.     BOOL Notify;
  287.  
  288.     ObtainSemaphore(&BufferSemaphore);
  289.  
  290.         /* Free the contents of the display buffer. */
  291.  
  292.     if(BufferLines)
  293.     {
  294.         APTR NewPoolHeader;
  295.  
  296.             /* If a new pool header is available, free the old
  297.              * pool and replace it with the new pool.
  298.              */
  299.  
  300.         if(NewPoolHeader = AsmCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT,SysBase))
  301.         {
  302.             AsmDeletePool(BufferPoolHeader,SysBase);
  303.  
  304.             BufferPoolHeader = NewPoolHeader;
  305.         }
  306.         else
  307.         {
  308.             LONG i;
  309.  
  310.             for(i = 0 ; i < Lines ; i++)
  311.             {
  312.                 if(BufferLines[i])
  313.                     FreeString(BufferLines[i]);
  314.             }
  315.         }
  316.  
  317.         FreeVecPooled(BufferLines);
  318.  
  319.         Lines = 0;
  320.  
  321.         MaxLines = BUFFER_GROW;
  322.  
  323.         BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR);
  324.  
  325.         Notify = TRUE;
  326.     }
  327.     else
  328.         Notify = FALSE;
  329.  
  330.     BufferSpace = 0;
  331.  
  332.     BufferChanged = FALSE;
  333.  
  334.     ReleaseSemaphore(&BufferSemaphore);
  335.  
  336.     if(Notify)
  337.     {
  338.         NotifyBuffer(&BufferTaskSemaphore,&BufferInfoData,SIG_UPDATE);
  339.         NotifyBuffer(&ReviewTaskSemaphore,&ReviewInfoData,SIG_UPDATE);
  340.     }
  341. }
  342.  
  343.     /* DeleteSearchInfo(struct SearchInfo *Info):
  344.      *
  345.      *    Free buffer allocated by CreateSearchInfo().
  346.      */
  347.  
  348. VOID
  349. DeleteSearchInfo(struct SearchInfo *Info)
  350. {
  351.     FreeVecPooled(Info);
  352. }
  353.  
  354.     /* CreateSearchInfo(STRPTR Pattern):
  355.      *
  356.      *    Create auxilary data required by SearchTextBuffer().
  357.      */
  358.  
  359. struct SearchInfo *
  360. CreateSearchInfo(STRPTR Pattern,BOOL Forward,BOOL IgnoreCase,BOOL WholeWords)
  361. {
  362.     struct SearchInfo *Info;
  363.  
  364.         /* Allocate the buffer. */
  365.  
  366.     if(Info = (struct SearchInfo *)AllocVecPooled(sizeof(struct SearchInfo),MEMF_ANY|MEMF_CLEAR))
  367.     {
  368.         LONG i;
  369.  
  370.             /* Determine pattern width. */
  371.  
  372.         Info->PatternWidth    = strlen(Pattern);
  373.         Info->IgnoreCase    = IgnoreCase;
  374.  
  375.         if(Info->PatternWidth == 1)
  376.         {
  377.             if(WordSeparators[Pattern[0]])
  378.                 WholeWords = FALSE;
  379.         }
  380.  
  381.         Info->WholeWords = WholeWords;
  382.  
  383.             /* Turn the pattern into upper case characters. */
  384.  
  385.         if(IgnoreCase)
  386.         {
  387.             for(i = 0 ; i <= Info->PatternWidth ; i++)
  388.                 Info->Pattern[i] = ToUpper(Pattern[i]);
  389.         }
  390.         else
  391.         {
  392.             for(i = 0 ; i <= Info->PatternWidth ; i++)
  393.                 Info->Pattern[i] = Pattern[i];
  394.         }
  395.  
  396.             /* Fill the entire range with the maximum pattern width. */
  397.  
  398.         for(i = 0 ; i < 256 ; i++)
  399.             Info->Distance[i] = Info->PatternWidth;
  400.  
  401.             /* Fill in the matching distances. */
  402.  
  403.         if(Forward)
  404.         {
  405.             for(i = 0 ; i < Info->PatternWidth - 1 ; i++)
  406.                 Info->Distance[Info->Pattern[i]] = Info->PatternWidth - 1 - i;
  407.         }
  408.         else
  409.         {
  410.             for(i = Info->PatternWidth - 1 ; i > 0 ; i--)
  411.                 Info->Distance[Info->Pattern[i]] = i;
  412.         }
  413.  
  414.             /* Restart from scratch. */
  415.  
  416.         Info->FoundY    = -1;
  417.         Info->Forward    = Forward;
  418.     }
  419.  
  420.     return(Info);
  421. }
  422.  
  423.     /* SearchTextBuffer():
  424.      *
  425.      *    String search function, based on the Boyer-Moore search
  426.      *    algorithm.
  427.      */
  428.  
  429. LONG
  430. SearchTextBuffer(struct SearchInfo *Info)
  431. {
  432.     if(BufferLines)
  433.     {
  434.         UBYTE    *Distance,*Pattern;
  435.         LONG LineWidth,PatternWidth;
  436.         STRPTR Line;
  437.         LONG SearchPosition,PatternIndex,LineIndex,LastSearchPosition;
  438.         LONG i;
  439.  
  440.             /* Extract the relevant data. */
  441.  
  442.         Distance            = Info->Distance;
  443.         Pattern            = Info->Pattern;
  444.         PatternWidth    = Info->PatternWidth;
  445.  
  446.         if(Info->WholeWords)
  447.         {
  448.                 /* Which direction are we to search? */
  449.  
  450.             if(Info->IgnoreCase)
  451.             {
  452.                 if(Info->Forward)
  453.                 {
  454.                         /* Update the search positions. */
  455.  
  456.                     if(Info->FoundY == -1)
  457.                     {
  458.                         Info->FoundX            = 0;
  459.                         Info->FoundY            = 0;
  460.                         LastSearchPosition    = 0;
  461.                     }
  462.                     else
  463.                     {
  464.                             /* Proceed to the next line. */
  465.  
  466.                         if(!(LastSearchPosition = Info->Index))
  467.                             Info->FoundY = (Info->FoundY + 1) % Lines;
  468.                     }
  469.  
  470.                         /* Run down the buffer. */
  471.  
  472.                     for(i = Info->FoundY ; i < Lines ; i++)
  473.                     {
  474.                         Line = BufferLines[i];
  475.  
  476.                             /* Is there anything to search for? */
  477.  
  478.                         if((LineWidth = Line[-1]) >= PatternWidth)
  479.                         {
  480.                                 /* Where are we to start searching? */
  481.  
  482.                             if(LastSearchPosition)
  483.                                 SearchPosition = LastSearchPosition;
  484.                             else
  485.                                 SearchPosition = PatternWidth;
  486.  
  487.                             do
  488.                             {
  489.                                     /* How many line characters
  490.                                      * match the pattern?
  491.                                      */
  492.  
  493.                                 PatternIndex    = PatternWidth - 1;
  494.                                 LineIndex        = SearchPosition - 1;
  495.  
  496.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  497.                                 {
  498.                                     LineIndex--;
  499.                                     PatternIndex--;
  500.                                 }
  501.  
  502.                                     /* Update the line search index
  503.                                      * for subsequent searches.
  504.                                      */
  505.  
  506.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  507.  
  508.                                     /* Found the pattern? */
  509.  
  510.                                 if(PatternIndex < 0)
  511.                                 {
  512.                                     LONG X = LineIndex + 1;
  513.  
  514.                                     if(X)
  515.                                     {
  516.                                         if(!WordSeparators[Line[X - 1]])
  517.                                             continue;
  518.                                         else
  519.                                         {
  520.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  521.                                                 continue;
  522.                                         }
  523.                                     }
  524.                                     else
  525.                                     {
  526.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  527.                                             continue;
  528.                                     }
  529.  
  530.                                         /* Store the position. */
  531.  
  532.                                     Info->FoundX    = LineIndex + 1;
  533.                                     Info->FoundY    = i;
  534.  
  535.                                         /* Remember column to start
  536.                                          * next search attempt at.
  537.                                          */
  538.  
  539.                                     if(SearchPosition <= LineWidth)
  540.                                         Info->Index = SearchPosition;
  541.                                     else
  542.                                         Info->Index = 0;
  543.  
  544.                                     return(i);
  545.                                 }
  546.                             }
  547.                             while(SearchPosition <= LineWidth);
  548.                         }
  549.  
  550.                             /* Reset search column. */
  551.  
  552.                         LastSearchPosition = 0;
  553.                     }
  554.                 }
  555.                 else
  556.                 {
  557.                         /* Update the search positions. */
  558.  
  559.                     if(Info->FoundY == -1)
  560.                     {
  561.                         Info->FoundX            = 0;
  562.                         Info->FoundY            = Lines - 1;
  563.                         LastSearchPosition    = 0;
  564.                     }
  565.                     else
  566.                     {
  567.                         if((LastSearchPosition = Info->Index) < 1)
  568.                         {
  569.                             if(Info->FoundY)
  570.                                 Info->FoundY--;
  571.                             else
  572.                                 Info->FoundY = Lines - 1;
  573.                         }
  574.                     }
  575.  
  576.                         /* Run down the buffer. */
  577.  
  578.                     for(i = Info->FoundY ; i >= 0 ; i--)
  579.                     {
  580.                         Line = BufferLines[i];
  581.  
  582.                             /* Is there anything to search for? */
  583.  
  584.                         if((LineWidth = Line[-1]) >= PatternWidth)
  585.                         {
  586.                                 /* Cast the magic spell of Boyer-Moore... */
  587.  
  588.                             if(LastSearchPosition < 1)
  589.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  590.                             else
  591.                                 SearchPosition = LastSearchPosition;
  592.  
  593.                             do
  594.                             {
  595.                                 PatternIndex = 0;
  596.                                 LineIndex     = SearchPosition - 1;
  597.  
  598.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  599.                                 {
  600.                                     LineIndex++;
  601.                                     PatternIndex++;
  602.                                 }
  603.  
  604.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  605.  
  606.                                 if(PatternIndex == PatternWidth)
  607.                                 {
  608.                                     LONG X = LineIndex - PatternWidth;
  609.  
  610.                                     if(X)
  611.                                     {
  612.                                         if(!WordSeparators[Line[X - 1]])
  613.                                             continue;
  614.                                         else
  615.                                         {
  616.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  617.                                                 continue;
  618.                                         }
  619.                                     }
  620.                                     else
  621.                                     {
  622.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  623.                                             continue;
  624.                                     }
  625.  
  626.                                     Info->FoundX    = LineIndex - PatternWidth;
  627.                                     Info->FoundY    = i;
  628.                                     Info->Index        = SearchPosition;
  629.  
  630.                                     return(i);
  631.                                 }
  632.                             }
  633.                             while(SearchPosition > 0);
  634.                         }
  635.  
  636.                         LastSearchPosition = 0;
  637.                     }
  638.                 }
  639.             }
  640.             else
  641.             {
  642.                 if(Info->Forward)
  643.                 {
  644.                         /* Update the search positions. */
  645.  
  646.                     if(Info->FoundY == -1)
  647.                     {
  648.                         Info->FoundX            = 0;
  649.                         Info->FoundY            = 0;
  650.                         LastSearchPosition    = 0;
  651.                     }
  652.                     else
  653.                     {
  654.                             /* Proceed to the next line. */
  655.  
  656.                         if(!(LastSearchPosition = Info->Index))
  657.                             Info->FoundY = (Info->FoundY + 1) % Lines;
  658.                     }
  659.  
  660.                         /* Run down the buffer. */
  661.  
  662.                     for(i = Info->FoundY ; i < Lines ; i++)
  663.                     {
  664.                         Line = BufferLines[i];
  665.  
  666.                             /* Is there anything to search for? */
  667.  
  668.                         if((LineWidth = Line[-1]) >= PatternWidth)
  669.                         {
  670.                                 /* Where are we to start searching? */
  671.  
  672.                             if(LastSearchPosition)
  673.                                 SearchPosition = LastSearchPosition;
  674.                             else
  675.                                 SearchPosition = PatternWidth;
  676.  
  677.                             do
  678.                             {
  679.                                     /* How many line characters
  680.                                      * match the pattern?
  681.                                      */
  682.  
  683.                                 PatternIndex    = PatternWidth - 1;
  684.                                 LineIndex        = SearchPosition - 1;
  685.  
  686.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  687.                                 {
  688.                                     LineIndex--;
  689.                                     PatternIndex--;
  690.                                 }
  691.  
  692.                                     /* Update the line search index
  693.                                      * for subsequent searches.
  694.                                      */
  695.  
  696.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  697.  
  698.                                     /* Found the pattern? */
  699.  
  700.                                 if(PatternIndex < 0)
  701.                                 {
  702.                                     LONG X = LineIndex + 1;
  703.  
  704.                                     if(X)
  705.                                     {
  706.                                         if(!WordSeparators[Line[X - 1]])
  707.                                             continue;
  708.                                         else
  709.                                         {
  710.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  711.                                                 continue;
  712.                                         }
  713.                                     }
  714.                                     else
  715.                                     {
  716.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  717.                                             continue;
  718.                                     }
  719.  
  720.                                         /* Store the position. */
  721.  
  722.                                     Info->FoundX    = LineIndex + 1;
  723.                                     Info->FoundY    = i;
  724.  
  725.                                         /* Remember column to start
  726.                                          * next search attempt at.
  727.                                          */
  728.  
  729.                                     if(SearchPosition <= LineWidth)
  730.                                         Info->Index = SearchPosition;
  731.                                     else
  732.                                         Info->Index = 0;
  733.  
  734.                                     return(i);
  735.                                 }
  736.                             }
  737.                             while(SearchPosition <= LineWidth);
  738.                         }
  739.  
  740.                             /* Reset search column. */
  741.  
  742.                         LastSearchPosition = 0;
  743.                     }
  744.                 }
  745.                 else
  746.                 {
  747.                         /* Update the search positions. */
  748.  
  749.                     if(Info->FoundY == -1)
  750.                     {
  751.                         Info->FoundX            = 0;
  752.                         Info->FoundY            = Lines - 1;
  753.                         LastSearchPosition    = 0;
  754.                     }
  755.                     else
  756.                     {
  757.                         if((LastSearchPosition = Info->Index) < 1)
  758.                         {
  759.                             if(Info->FoundY)
  760.                                 Info->FoundY--;
  761.                             else
  762.                                 Info->FoundY = Lines - 1;
  763.                         }
  764.                     }
  765.  
  766.                         /* Run down the buffer. */
  767.  
  768.                     for(i = Info->FoundY ; i >= 0 ; i--)
  769.                     {
  770.                         Line = BufferLines[i];
  771.  
  772.                             /* Is there anything to search for? */
  773.  
  774.                         if((LineWidth = Line[-1]) >= PatternWidth)
  775.                         {
  776.                                 /* Cast the magic spell of Boyer-Moore... */
  777.  
  778.                             if(LastSearchPosition < 1)
  779.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  780.                             else
  781.                                 SearchPosition = LastSearchPosition;
  782.  
  783.                             do
  784.                             {
  785.                                 PatternIndex = 0;
  786.                                 LineIndex = SearchPosition - 1;
  787.  
  788.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  789.                                 {
  790.                                     LineIndex++;
  791.                                     PatternIndex++;
  792.                                 }
  793.  
  794.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  795.  
  796.                                 if(PatternIndex == PatternWidth)
  797.                                 {
  798.                                     LONG X = LineIndex - PatternWidth;
  799.  
  800.                                     if(X)
  801.                                     {
  802.                                         if(!WordSeparators[Line[X - 1]])
  803.                                             continue;
  804.                                         else
  805.                                         {
  806.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  807.                                                 continue;
  808.                                         }
  809.                                     }
  810.                                     else
  811.                                     {
  812.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  813.                                             continue;
  814.                                     }
  815.  
  816.                                     Info->FoundX    = LineIndex - PatternWidth;
  817.                                     Info->FoundY    = i;
  818.                                     Info->Index    = SearchPosition;
  819.  
  820.                                     return(i);
  821.                                 }
  822.                             }
  823.                             while(SearchPosition > 0);
  824.                         }
  825.  
  826.                         LastSearchPosition = 0;
  827.                     }
  828.                 }
  829.             }
  830.         }
  831.         else
  832.         {
  833.                 /* Which direction are we to search? */
  834.  
  835.             if(Info->IgnoreCase)
  836.             {
  837.                 if(Info->Forward)
  838.                 {
  839.                         /* Update the search positions. */
  840.  
  841.                     if(Info->FoundY == -1)
  842.                     {
  843.                         Info->FoundX            = 0;
  844.                         Info->FoundY            = 0;
  845.                         LastSearchPosition    = 0;
  846.                     }
  847.                     else
  848.                     {
  849.                             /* Proceed to the next line. */
  850.  
  851.                         if(!(LastSearchPosition = Info->Index))
  852.                             Info->FoundY = (Info->FoundY + 1) % Lines;
  853.                     }
  854.  
  855.                         /* Run down the buffer. */
  856.  
  857.                     for(i = Info->FoundY ; i < Lines ; i++)
  858.                     {
  859.                         Line = BufferLines[i];
  860.  
  861.                             /* Is there anything to search for? */
  862.  
  863.                         if((LineWidth = Line[-1]) >= PatternWidth)
  864.                         {
  865.                                 /* Where are we to start searching? */
  866.  
  867.                             if(LastSearchPosition)
  868.                                 SearchPosition = LastSearchPosition;
  869.                             else
  870.                                 SearchPosition = PatternWidth;
  871.  
  872.                             do
  873.                             {
  874.                                     /* How many line characters
  875.                                      * match the pattern?
  876.                                      */
  877.  
  878.                                 PatternIndex    = PatternWidth - 1;
  879.                                 LineIndex        = SearchPosition - 1;
  880.  
  881.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  882.                                 {
  883.                                     LineIndex--;
  884.                                     PatternIndex--;
  885.                                 }
  886.  
  887.                                     /* Update the line search index
  888.                                      * for subsequent searches.
  889.                                      */
  890.  
  891.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  892.  
  893.                                     /* Found the pattern? */
  894.  
  895.                                 if(PatternIndex < 0)
  896.                                 {
  897.                                         /* Store the position. */
  898.  
  899.                                     Info->FoundX    = LineIndex + 1;
  900.                                     Info->FoundY    = i;
  901.  
  902.                                         /* Remember column to start
  903.                                          * next search attempt at.
  904.                                          */
  905.  
  906.                                     if(SearchPosition <= LineWidth)
  907.                                         Info->Index = SearchPosition;
  908.                                     else
  909.                                         Info->Index = 0;
  910.  
  911.                                     return(i);
  912.                                 }
  913.                             }
  914.                             while(SearchPosition <= LineWidth);
  915.                         }
  916.  
  917.                             /* Reset search column. */
  918.  
  919.                         LastSearchPosition = 0;
  920.                     }
  921.                 }
  922.                 else
  923.                 {
  924.                         /* Update the search positions. */
  925.  
  926.                     if(Info->FoundY == -1)
  927.                     {
  928.                         Info->FoundX            = 0;
  929.                         Info->FoundY            = Lines - 1;
  930.                         LastSearchPosition    = 0;
  931.                     }
  932.                     else
  933.                     {
  934.                         if((LastSearchPosition = Info->Index) < 1)
  935.                         {
  936.                             if(Info->FoundY)
  937.                                 Info->FoundY--;
  938.                             else
  939.                                 Info->FoundY = Lines - 1;
  940.                         }
  941.                     }
  942.  
  943.                         /* Run down the buffer. */
  944.  
  945.                     for(i = Info->FoundY ; i >= 0 ; i--)
  946.                     {
  947.                         Line = BufferLines[i];
  948.  
  949.                             /* Is there anything to search for? */
  950.  
  951.                         if((LineWidth = Line[-1]) >= PatternWidth)
  952.                         {
  953.                                 /* Cast the magic spell of Boyer-Moore... */
  954.  
  955.                             if(LastSearchPosition < 1)
  956.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  957.                             else
  958.                                 SearchPosition = LastSearchPosition;
  959.  
  960.                             do
  961.                             {
  962.                                 PatternIndex = 0;
  963.                                 LineIndex = SearchPosition - 1;
  964.  
  965.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  966.                                 {
  967.                                     LineIndex++;
  968.                                     PatternIndex++;
  969.                                 }
  970.  
  971.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  972.  
  973.                                 if(PatternIndex == PatternWidth)
  974.                                 {
  975.                                     Info->FoundX    = LineIndex - PatternWidth;
  976.                                     Info->FoundY    = i;
  977.                                     Info->Index        = SearchPosition;
  978.  
  979.                                     return(i);
  980.                                 }
  981.                             }
  982.                             while(SearchPosition > 0);
  983.                         }
  984.  
  985.                         LastSearchPosition = 0;
  986.                     }
  987.                 }
  988.             }
  989.             else
  990.             {
  991.                 if(Info->Forward)
  992.                 {
  993.                         /* Update the search positions. */
  994.  
  995.                     if(Info->FoundY == -1)
  996.                     {
  997.                         Info->FoundX            = 0;
  998.                         Info->FoundY            = 0;
  999.                         LastSearchPosition    = 0;
  1000.                     }
  1001.                     else
  1002.                     {
  1003.                             /* Proceed to the next line. */
  1004.  
  1005.                         if(!(LastSearchPosition = Info->Index))
  1006.                             Info->FoundY = (Info->FoundY + 1) % Lines;
  1007.                     }
  1008.  
  1009.                         /* Run down the buffer. */
  1010.  
  1011.                     for(i = Info->FoundY ; i < Lines ; i++)
  1012.                     {
  1013.                         Line = BufferLines[i];
  1014.  
  1015.                             /* Is there anything to search for? */
  1016.  
  1017.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1018.                         {
  1019.                                 /* Where are we to start searching? */
  1020.  
  1021.                             if(LastSearchPosition)
  1022.                                 SearchPosition = LastSearchPosition;
  1023.                             else
  1024.                                 SearchPosition = PatternWidth;
  1025.  
  1026.                             do
  1027.                             {
  1028.                                     /* How many line characters
  1029.                                      * match the pattern?
  1030.                                      */
  1031.  
  1032.                                 PatternIndex    = PatternWidth - 1;
  1033.                                 LineIndex        = SearchPosition - 1;
  1034.  
  1035.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  1036.                                 {
  1037.                                     LineIndex--;
  1038.                                     PatternIndex--;
  1039.                                 }
  1040.  
  1041.                                     /* Update the line search index
  1042.                                      * for subsequent searches.
  1043.                                      */
  1044.  
  1045.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  1046.  
  1047.                                     /* Found the pattern? */
  1048.  
  1049.                                 if(PatternIndex < 0)
  1050.                                 {
  1051.                                         /* Store the position. */
  1052.  
  1053.                                     Info->FoundX    = LineIndex + 1;
  1054.                                     Info->FoundY    = i;
  1055.  
  1056.                                         /* Remember column to start
  1057.                                          * next search attempt at.
  1058.                                          */
  1059.  
  1060.                                     if(SearchPosition <= LineWidth)
  1061.                                         Info->Index = SearchPosition;
  1062.                                     else
  1063.                                         Info->Index = 0;
  1064.  
  1065.                                     return(i);
  1066.                                 }
  1067.                             }
  1068.                             while(SearchPosition <= LineWidth);
  1069.                         }
  1070.  
  1071.                             /* Reset search column. */
  1072.  
  1073.                         LastSearchPosition = 0;
  1074.                     }
  1075.                 }
  1076.                 else
  1077.                 {
  1078.                         /* Update the search positions. */
  1079.  
  1080.                     if(Info->FoundY == -1)
  1081.                     {
  1082.                         Info->FoundX            = 0;
  1083.                         Info->FoundY            = Lines - 1;
  1084.                         LastSearchPosition    = 0;
  1085.                     }
  1086.                     else
  1087.                     {
  1088.                         if((LastSearchPosition = Info->Index) < 1)
  1089.                         {
  1090.                             if(Info->FoundY)
  1091.                                 Info->FoundY--;
  1092.                             else
  1093.                                 Info->FoundY = Lines - 1;
  1094.                         }
  1095.                     }
  1096.  
  1097.                         /* Run down the buffer. */
  1098.  
  1099.                     for(i = Info->FoundY ; i >= 0 ; i--)
  1100.                     {
  1101.                         Line = BufferLines[i];
  1102.  
  1103.                             /* Is there anything to search for? */
  1104.  
  1105.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1106.                         {
  1107.                                 /* Cast the magic spell of Boyer-Moore... */
  1108.  
  1109.                             if(LastSearchPosition < 1)
  1110.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1111.                             else
  1112.                                 SearchPosition = LastSearchPosition;
  1113.  
  1114.                             do
  1115.                             {
  1116.                                 PatternIndex = 0;
  1117.                                 LineIndex = SearchPosition - 1;
  1118.  
  1119.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  1120.                                 {
  1121.                                     LineIndex++;
  1122.                                     PatternIndex++;
  1123.                                 }
  1124.  
  1125.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  1126.  
  1127.                                 if(PatternIndex == PatternWidth)
  1128.                                 {
  1129.                                     Info->FoundX    = LineIndex - PatternWidth;
  1130.                                     Info->FoundY    = i;
  1131.                                     Info->Index    = SearchPosition;
  1132.  
  1133.                                     return(i);
  1134.                                 }
  1135.                             }
  1136.                             while(SearchPosition > 0);
  1137.                         }
  1138.  
  1139.                         LastSearchPosition = 0;
  1140.                     }
  1141.                 }
  1142.             }
  1143.         }
  1144.     }
  1145.  
  1146.     return(-1);
  1147. }
  1148.  
  1149. STATIC ULONG SAVE_DS ASM
  1150. HistoryFunc(REG(a0) struct Hook *Hook,REG(a2) APTR Unused,REG(a1) STRPTR NewString)
  1151. {
  1152.     struct List *List = (struct List *)Hook->h_Data;
  1153.  
  1154.     if(NewString)
  1155.     {
  1156.         struct Node *Node = CreateNode(NewString);
  1157.  
  1158.         if(Node)
  1159.             AddTail(List,Node);
  1160.         else
  1161.             return(FALSE);
  1162.     }
  1163.     else
  1164.     {
  1165.         struct Node *Node = RemHead(List);
  1166.  
  1167.         FreeVecPooled(Node);
  1168.     }
  1169.  
  1170.     return(TRUE);
  1171. }
  1172.  
  1173. BOOL
  1174. HandleSearchMessage(struct SearchContext *Context,struct IntuiMessage **MessagePtr)
  1175. {
  1176.     struct IntuiMessage *Message;
  1177.     BOOL Done;
  1178.  
  1179.     Done = FALSE;
  1180.  
  1181.     if(Message = GT_FilterIMsg(*MessagePtr))
  1182.     {
  1183.         ULONG MsgClass,MsgQualifier;
  1184.         struct Gadget *MsgGadget;
  1185.         UWORD MsgCode;
  1186.  
  1187.         MsgClass            = Message->Class;
  1188.         MsgQualifier    = Message->Qualifier;
  1189.         MsgGadget        = (struct Gadget *)Message->IAddress;
  1190.         MsgCode            = Message->Code;
  1191.  
  1192.         LT_HandleInput(Context->SearchHandle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  1193.  
  1194.         if(MsgClass == IDCMP_CLOSEWINDOW)
  1195.             Done = TRUE;
  1196.  
  1197.         if(MsgClass == IDCMP_GADGETUP)
  1198.         {
  1199.             switch(MsgGadget->GadgetID)
  1200.             {
  1201.                 case GAD_STRING:
  1202.  
  1203.                     if(MsgCode == '\r')
  1204.                     {
  1205.                         if(Context->LocalBuffer[0])
  1206.                         {
  1207.                             strcpy(Context->Buffer,Context->LocalBuffer);
  1208.  
  1209.                             Context->Ok = TRUE;
  1210.  
  1211.                             LT_PressButton(Context->SearchHandle,GAD_OK);
  1212.                         }
  1213.                         else
  1214.                             LT_PressButton(Context->SearchHandle,GAD_CANCEL);
  1215.  
  1216.                         Done = TRUE;
  1217.                     }
  1218.  
  1219.                     break;
  1220.  
  1221.                 case GAD_OK:
  1222.  
  1223.                     LT_UpdateStrings(Context->SearchHandle);
  1224.  
  1225.                     if(Context->LocalBuffer[0])
  1226.                     {
  1227.                         strcpy(Context->Buffer,Context->LocalBuffer);
  1228.  
  1229.                         Context->Ok = TRUE;
  1230.                     }
  1231.  
  1232.                     Done = TRUE;
  1233.  
  1234.                     break;
  1235.  
  1236.                 case GAD_CANCEL:
  1237.  
  1238.                     Done = TRUE;
  1239.  
  1240.                     break;
  1241.             }
  1242.         }
  1243.  
  1244.         GT_PostFilterIMsg(Message);
  1245.     }
  1246.  
  1247.     ReplyMsg((struct Message *)*MessagePtr);
  1248.  
  1249.     *MessagePtr = NULL;
  1250.  
  1251.     return(Done);
  1252. }
  1253.  
  1254. VOID
  1255. DeleteSearchContext(struct SearchContext *Context)
  1256. {
  1257.     if(Context)
  1258.     {
  1259.         LT_DeleteHandle(Context->SearchHandle);
  1260.  
  1261.         FreeVecPooled(Context);
  1262.     }
  1263. }
  1264.  
  1265. struct SearchContext *
  1266. CreateSearchContext(struct Window *ParentWindow,STRPTR Buffer,struct Hook *HistoryHook,struct List *HistoryHookList,BOOL *Forward,BOOL *IgnoreCase,BOOL *WholeWords)
  1267. {
  1268.     struct SearchContext *Context;
  1269.  
  1270.     if(Context = (struct SearchContext *)AllocVecPooled(sizeof(struct SearchContext),MEMF_ANY | MEMF_CLEAR))
  1271.     {
  1272.         struct LayoutHandle *Handle;
  1273.  
  1274.         Context->Buffer = Buffer;
  1275.  
  1276.         InitHook(HistoryHook,(HOOKFUNC)HistoryFunc,HistoryHookList);
  1277.  
  1278.         if(Handle = LT_CreateHandleTags(ParentWindow->WScreen,
  1279.             LAHN_LocaleHook,    &LocaleHook,
  1280.         TAG_DONE))
  1281.         {
  1282.             struct Window *Window;
  1283.  
  1284.             LT_New(Handle,
  1285.                 LA_Type,    VERTICAL_KIND,
  1286.             TAG_DONE);
  1287.             {
  1288.                 LT_New(Handle,
  1289.                     LA_Type,    HORIZONTAL_KIND,
  1290.                 TAG_DONE);
  1291.                 {
  1292.                     LT_New(Handle,
  1293.                         LA_Type,    VERTICAL_KIND,
  1294.                     TAG_DONE);
  1295.                     {
  1296.                         LT_New(Handle,
  1297.                             LA_Type,                    STRING_KIND,
  1298.                             LA_LabelID,                MSG_V36_0788,
  1299.                             LA_STRPTR,                Context->LocalBuffer,
  1300.                             LA_Chars,                30,
  1301.                             LA_ID,                    GAD_STRING,
  1302.                             LAST_HistoryLines,    MAX(Config->CaptureConfig->SearchHistory,1),
  1303.                             LAST_HistoryHook,        HistoryHook,
  1304.                             GTST_MaxChars,            sizeof(Context->LocalBuffer) - 1,
  1305.                         TAG_DONE);
  1306.  
  1307.                         LT_EndGroup(Handle);
  1308.                     }
  1309.  
  1310.                     LT_New(Handle,
  1311.                         LA_Type,    VERTICAL_KIND,
  1312.                     TAG_DONE);
  1313.                     {
  1314.                         LT_New(Handle,
  1315.                             LA_Type,YBAR_KIND,
  1316.                         TAG_DONE);
  1317.  
  1318.                         LT_EndGroup(Handle);
  1319.                     }
  1320.  
  1321.                     LT_New(Handle,
  1322.                         LA_Type,    VERTICAL_KIND,
  1323.                     TAG_DONE);
  1324.                     {
  1325.                         LT_New(Handle,
  1326.                             LA_Type,        CHECKBOX_KIND,
  1327.                             LA_LabelID,    MSG_TERMBUFFER_SEARCH_FORWARD_TXT,
  1328.                             LA_BYTE,        Forward,
  1329.                         TAG_DONE);
  1330.  
  1331.                         LT_New(Handle,
  1332.                             LA_Type,        CHECKBOX_KIND,
  1333.                             LA_LabelID,    MSG_TEXTBUFFER_IGNORE_CASE_GAD,
  1334.                             LA_BYTE,        IgnoreCase,
  1335.                         TAG_DONE);
  1336.  
  1337.                         LT_New(Handle,
  1338.                             LA_Type,        CHECKBOX_KIND,
  1339.                             LA_LabelID,    MSG_SEARCH_ONLY_WHOLE_WORDS_TXT,
  1340.                             LA_BYTE,        WholeWords,
  1341.                         TAG_DONE);
  1342.  
  1343.                         LT_EndGroup(Handle);
  1344.                     }
  1345.  
  1346.                     LT_EndGroup(Handle);
  1347.                 }
  1348.  
  1349.                 LT_New(Handle,
  1350.                     LA_Type,    VERTICAL_KIND,
  1351.                 TAG_DONE);
  1352.                 {
  1353.                     LT_New(Handle,
  1354.                         LA_Type,            XBAR_KIND,
  1355.                         LAXB_FullSize,    TRUE,
  1356.                     TAG_DONE);
  1357.  
  1358.                     LT_EndGroup(Handle);
  1359.                 }
  1360.  
  1361.                 LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1362.                     LAGR_SameSize,    TRUE,
  1363.                     LAGR_Spread,    TRUE,
  1364.                 TAG_DONE);
  1365.                 {
  1366.                     LT_New(Handle,
  1367.                         LA_Type,                BUTTON_KIND,
  1368.                         LA_LabelID,            MSG_TERMXPR_OKAY_GAD,
  1369.                         LA_ID,                GAD_OK,
  1370.                         LABT_ReturnKey,    TRUE,
  1371.                         LABT_ExtraFat,        TRUE,
  1372.                     TAG_DONE);
  1373.  
  1374.                     LT_New(Handle,
  1375.                         LA_Type,                BUTTON_KIND,
  1376.                         LA_LabelID,            MSG_GLOBAL_CANCEL_GAD,
  1377.                         LA_ID,                GAD_CANCEL,
  1378.                         LABT_EscKey,        TRUE,
  1379.                         LABT_ExtraFat,        TRUE,
  1380.                     TAG_DONE);
  1381.  
  1382.                     LT_EndGroup(Handle);
  1383.                 }
  1384.  
  1385.                 LT_EndGroup(Handle);
  1386.             }
  1387.  
  1388.             if(Window = LT_Build(Handle,
  1389.                 LAWN_TitleID,        MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT,
  1390.                 LAWN_IDCMP,            IDCMP_CLOSEWINDOW,
  1391.                 LAWN_HelpHook,        &GuideHook,
  1392.                 LAWN_Parent,        ParentWindow,
  1393.                 LAWN_UserPort,        ParentWindow->UserPort,
  1394.                 WA_DepthGadget,    TRUE,
  1395.                 WA_CloseGadget,    TRUE,
  1396.                 WA_DragBar,            TRUE,
  1397.                 WA_RMBTrap,            TRUE,
  1398.                 WA_Activate,        TRUE,
  1399.                 WA_SimpleRefresh,    TRUE,
  1400.             TAG_DONE))
  1401.             {
  1402.                 LT_Activate(Handle,GAD_STRING);
  1403.  
  1404.                 Context->SearchHandle = Handle;
  1405.                 Context->SearchWindow = Window;
  1406.  
  1407.                 return(Context);
  1408.             }
  1409.         }
  1410.  
  1411.         FreeVecPooled(Context);
  1412.     }
  1413.  
  1414.     return(NULL);
  1415. }
  1416.